﻿#define _CRT_SECURE_NO_WARNINGS 1
#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_WriteCommand(unsigned char Command);
void LCD_WriteData(unsigned char Data);
void LCD_SetCursor(unsigned char Line, unsigned char Column);
void LCD_Init();
void LCD_ShowChar(unsigned char Line, unsigned char Column, char Char);
void LCD_ShowString(unsigned char Line, unsigned char Column, char* String);
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length);
void LCD_ShowHexNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length);
void LCD_ShowBinNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length);
void LCD_Clear(void);
void LCD_IsShowCursor(unsigned char State);
void LCD_Show16Char(unsigned char Line, unsigned char Column, char* String);

#endif
#include <REGX52.H>

/*引脚配置*/
sbit LCD_RS = P2 ^ 6;
sbit LCD_RW = P2 ^ 5;
sbit LCD_EN = P2 ^ 7;
#define LCD_DataPort P0

/*函数定义*/
/**
  * 函    数：LCD1602私有延时函数，延时约50us
  * 参    数：无
  * 返 回 值：无
  */
void LCD_Delay50us(void)	//12T@11.0592MHz
{
	unsigned char i;
	i = 20;
	while (--i);
}

/**
  * 函    数：LCD1602私有延时函数，延时约2ms
  * 参    数：无
  * 返 回 值：无
  */
void LCD_Delay2ms(void)	//12T@11.0592MHz
{
	unsigned char i, j;
	i = 4;
	j = 146;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * 函    数：LCD1602写指令
  * 参    数：Command 要写入的指令
  * 返 回 值：无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS = 0;
	LCD_RW = 0;
	LCD_DataPort = Command;
	LCD_EN = 1;
	LCD_Delay50us();
	LCD_EN = 0;
	LCD_Delay50us();
}

/**
  * 函    数：LCD1602写数据
  * 参    数：Data 要写入的数据
  * 返 回 值：无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS = 1;
	LCD_RW = 0;
	LCD_DataPort = Data;
	LCD_EN = 1;
	LCD_Delay50us();
	LCD_EN = 0;
	LCD_Delay50us();
}

/**
  * 函    数：LCD1602设置光标位置
  * 参    数：Line 行位置，范围：1~2
  * 参    数：Column 列位置，范围：1~16
  * 返 回 值：无
  */
void LCD_SetCursor(unsigned char Line, unsigned char Column)
{
	if (Line == 1)
	{
		LCD_WriteCommand(0x80 | (Column - 1));
	}
	else if (Line == 2)
	{
		LCD_WriteCommand(0x80 | (Column - 1 + 0x40));
	}
}

/**
  * 函    数：LCD1602初始化函数
  * 参    数：无
  * 返 回 值：无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);	//八位数据接口，两行显示，5*7点阵
	LCD_WriteCommand(0x0C);	//显示开，光标关，闪烁关
	LCD_WriteCommand(0x06);	//数据读写操作后，光标自动加一，画面不动
	LCD_WriteCommand(0x01);	//光标复位，清屏
	LCD_Delay2ms();	//清屏指令执行需要较长时间，需要较长的延时
}

/**
  * 函    数：在LCD1602指定位置上显示一个字符
  * 参    数：Line 行位置，范围：1~2
  * 参    数：Column 列位置，范围：1~16
  * 参    数：Char 要显示的字符
  * 返 回 值：无
  */
void LCD_ShowChar(unsigned char Line, unsigned char Column, char Char)
{
	LCD_SetCursor(Line, Column);
	LCD_WriteData(Char);
}

/**
  * 函    数：在LCD1602指定位置开始显示所给字符串
  * 参    数：Line 起始行位置，范围：1~2
  * 参    数：Column 起始列位置，范围：1~16
  * 参    数：String 要显示的字符串
  * 返 回 值：无
  */
void LCD_ShowString(unsigned char Line, unsigned char Column, char* String)
{
	unsigned char i;
	LCD_SetCursor(Line, Column);
	for (i = 0; String[i] != '\0'; i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * 函    数：返回值=X的Y次方
  */
int LCD_Pow(int X, int Y)
{
	unsigned char i;
	int Result = 1;
	for (i = 0; i < Y; i++)
	{
		Result *= X;
	}
	return Result;
}

/**
  * 函    数：在LCD1602指定位置开始显示所给数字
  * 参    数：Line 起始行位置，范围：1~2
  * 参    数：Column 起始列位置，范围：1~16
  * 参    数：Number 要显示的数字，范围：0~65535
  * 参    数：Length 要显示数字的长度，范围：1~5
  * 返 回 值：无
  */
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line, Column);
	for (i = Length; i > 0; i--)
	{
		LCD_WriteData(Number / LCD_Pow(10, i - 1) % 10 + '0');
	}
}

/**
  * 函    数：在LCD1602指定位置开始以有符号十进制显示所给数字
  * 参    数：Line 起始行位置，范围：1~2
  * 参    数：Column 起始列位置，范围：1~16
  * 参    数：Number 要显示的数字，范围：-32768~32767
  * 参    数：Length 要显示数字的长度，范围：1~5
  * 返 回 值：无
  */
void LCD_ShowSignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line, Column);
	if (Number >= 0)
	{
		LCD_WriteData('+');
		Number1 = Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1 = -Number;
	}
	for (i = Length; i > 0; i--)
	{
		LCD_WriteData(Number1 / LCD_Pow(10, i - 1) % 10 + '0');
	}
}

/**
  * 函    数：在LCD1602指定位置开始以十六进制显示所给数字
  * 参    数：Line 起始行位置，范围：1~2
  * 参    数：Column 起始列位置，范围：1~16
  * 参    数：Number 要显示的数字，范围：0~0xFFFF
  * 参    数：Length 要显示数字的长度，范围：1~4
  * 返 回 值：无
  */
void LCD_ShowHexNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
	unsigned char i, SingleNumber;
	LCD_SetCursor(Line, Column);
	for (i = Length; i > 0; i--)
	{
		SingleNumber = Number / LCD_Pow(16, i - 1) % 16;
		if (SingleNumber < 10)
		{
			LCD_WriteData(SingleNumber + '0');
		}
		else
		{
			LCD_WriteData(SingleNumber - 10 + 'A');
		}
	}
}

/**
  * 函    数：在LCD1602指定位置开始以二进制显示所给数字
  * 参    数：Line 起始行位置，范围：1~2
  * 参    数：Column 起始列位置，范围：1~16
  * 参    数：Number 要显示的数字，范围：0~1111 1111 1111 1111
  * 参    数：Length 要显示数字的长度，范围：1~16
  * 返 回 值：无
  */
void LCD_ShowBinNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line, Column);
	for (i = Length; i > 0; i--)
	{
		LCD_WriteData(Number / LCD_Pow(2, i - 1) % 2 + '0');
	}
}

/**
  * 函    数：LCD1602的光标复位，清屏
  * 参    数：无
  * 返 回 值：无
  */
void LCD_Clear(void)
{
	LCD_WriteCommand(0x01);
	LCD_Delay2ms();
}

/**
  * 函    数：LCD1602设置光标是否显示
  * 参    数：State 光标状态，1：显示，0：不显示
  * 返 回 值：无
  */
void LCD_IsShowCursor(unsigned char State)
{
	if (State) { LCD_WriteCommand(0x0E); }
	else { LCD_WriteCommand(0x0C); }
}
#ifndef __MATRIXKEYSCAN_H__
#define __MATRIXKEYSCAN_H__

unsigned char MatrixKey(void);
void MatrixKey_Tick(void);

#endif
#include <REGX52.H>

#define Matrix_Port P1	//矩阵按键接口

unsigned char KeyNumber;

/**
  * 函    数：获取矩阵按键键码
  * 参    数：无
  * 返 回 值：按下按键的键码，范围：0~48，0表示无按键按下
  * 说    明：在下一次检测按键之前，第二次获取键码一定会返回0
  */
unsigned char MatrixKey(void)
{
	unsigned char KeyTemp = 0;
	KeyTemp = KeyNumber;
	KeyNumber = 0;
	return KeyTemp;
}

/**
  * 函    数：检测当前按下的按键，无消抖及松手检测
  * 参    数：无
  * 返 回 值：按下按键的键值，范围：0~16，无按键按下时返回值为0
  */
unsigned char Key_GetState()
{
	unsigned char KeyValue = 0;
	unsigned char i = 0;

	Matrix_Port = 0x0F;	//给所有行赋值0，列全为1
	i = 2; while (i--);	//适当延时，延时5us
	if (Matrix_Port != 0x0F)
	{
		Matrix_Port = 0x0F;	//测试列
		i = 2; while (i--);
		switch (Matrix_Port)	//所有行拉低，检测哪一列按下
		{
		case 0x07:KeyValue = 1; break;
		case 0x0B:KeyValue = 2; break;
		case 0x0D:KeyValue = 3; break;
		case 0x0E:KeyValue = 4; break;
		default:break;
		}
		Matrix_Port = 0xF0;	//测试行
		i = 2; while (i--);
		switch (Matrix_Port)	//所有列拉低，检测哪一行按下
		{
		case 0x70:KeyValue = KeyValue; break;
		case 0xB0:KeyValue = KeyValue + 4; break;
		case 0xD0:KeyValue = KeyValue + 8; break;
		case 0xE0:KeyValue = KeyValue + 12; break;
		default:break;
		}
	}
	else
	{
		KeyValue = 0;
	}

	return KeyValue;
}

/**
  * 函    数：矩阵按键驱动函数，在中断中调用
  * 参    数：无
  * 返 回 值：无
  */
void MatrixKey_Tick(void)
{
	static unsigned char NowState, LastState;
	static unsigned int KeyCount;

	LastState = NowState;	//更新上一次的键值
	NowState = Key_GetState();	//获取当前的键值

	//如果上个时间点按键未按下，这个时间点按键按下，则是按下瞬间
	if (LastState == 0)
	{
		switch (NowState)
		{
		case 1:KeyNumber = 1; break;
		case 2:KeyNumber = 2; break;
		case 3:KeyNumber = 3; break;
		case 4:KeyNumber = 4; break;
		case 5:KeyNumber = 5; break;
		case 6:KeyNumber = 6; break;
		case 7:KeyNumber = 7; break;
		case 8:KeyNumber = 8; break;
		case 9:KeyNumber = 9; break;
		case 10:KeyNumber = 10; break;
		case 11:KeyNumber = 11; break;
		case 12:KeyNumber = 12; break;
		case 13:KeyNumber = 13; break;
		case 14:KeyNumber = 14; break;
		case 15:KeyNumber = 15; break;
		case 16:KeyNumber = 16; break;
		default:break;
		}
	}

	//如果上个时间点按键按下，这个时间点按键还是按下，则是长按
	if (LastState && NowState)
	{
		KeyCount++;

		if (KeyCount % 50 == 0)	//定时器中断函数中每隔20ms检测一次按键
		{	//长按后每隔1s返回一次长按的键码
			if (LastState == 1 && NowState == 1) { KeyNumber = 17; }
			else if (LastState == 2 && NowState == 2) { KeyNumber = 18; }
			else if (LastState == 3 && NowState == 3) { KeyNumber = 19; }
			else if (LastState == 4 && NowState == 4) { KeyNumber = 20; }
			else if (LastState == 5 && NowState == 5) { KeyNumber = 21; }
			else if (LastState == 6 && NowState == 6) { KeyNumber = 22; }
			else if (LastState == 7 && NowState == 7) { KeyNumber = 23; }
			else if (LastState == 8 && NowState == 8) { KeyNumber = 24; }
			else if (LastState == 9 && NowState == 9) { KeyNumber = 25; }
			else if (LastState == 10 && NowState == 10) { KeyNumber = 26; }
			else if (LastState == 11 && NowState == 11) { KeyNumber = 27; }
			else if (LastState == 12 && NowState == 12) { KeyNumber = 28; }
			else if (LastState == 13 && NowState == 13) { KeyNumber = 29; }
			else if (LastState == 14 && NowState == 14) { KeyNumber = 30; }
			else if (LastState == 15 && NowState == 15) { KeyNumber = 31; }
			else if (LastState == 16 && NowState == 16) { KeyNumber = 32; }
		}
	}
	else
	{
		KeyCount = 0;
	}

	//如果上个时间点按键按下，这个时间点按键未按下，则是松手瞬间
	if (NowState == 0)
	{
		switch (LastState)
		{
		case 1:KeyNumber = 33; break;
		case 2:KeyNumber = 34; break;
		case 3:KeyNumber = 35; break;
		case 4:KeyNumber = 36; break;
		case 5:KeyNumber = 37; break;
		case 6:KeyNumber = 38; break;
		case 7:KeyNumber = 39; break;
		case 8:KeyNumber = 40; break;
		case 9:KeyNumber = 41; break;
		case 10:KeyNumber = 42; break;
		case 11:KeyNumber = 43; break;
		case 12:KeyNumber = 44; break;
		case 13:KeyNumber = 45; break;
		case 14:KeyNumber = 46; break;
		case 15:KeyNumber = 47; break;
		case 16:KeyNumber = 48; break;
		default:break;
		}
	}

}
#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif
#include <REGX52.H>

/**
  * 函    数：定时器0初始化
  * 参    数：无
  * 返 回 值：无
  */
void Timer0_Init(void)
{
	//	AUXR&=0x7F;	//定时器时钟12T模式（STC89C52RC是12T单片机，无需设置）
	TMOD &= 0xF0;	//设置定时器模式（高四位不变，低四位清零）
	TMOD |= 0x01;	//设置定时器模式（通过低四位设为16位不自动重装）
	TL0 = 0x00;	//设置定时初值，定时10ms，12T@11.0592MHz
	TH0 = 0xDC;	//设置定时初值，定时10ms，12T@11.0592MHz
	TF0 = 0;	//清除TF0标志
	TR0 = 1;	//定时器0开始计时
	ET0 = 1;	//打开定时器0中断允许
	EA = 1;	//打开总中断
	PT0 = 0;	//当PT0=0时，定时器0为低优先级，当PT0=1时，定时器0为高优先级
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1	//定时器0中断函数
{
	static unsigned int T0Count;	//定义静态变量
	TL0=0x00;	//设置定时初值，定时10ms，12T@11.0592MHz
	TH0=0xDC;	//设置定时初值，定时10ms，12T@11.0592MHz
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;

	}
}
*/
/*by甘腾胜@20250423
【效果查看/操作演示】B站搜索“甘腾胜”或“gantengsheng”查看
【单片机】STC89C52RC
【频率】12T@11.0592MHz
【外设】LCD1602、矩阵按键
【简单的原理分析】https://blog.csdn.net/gantengsheng/article/details/143581157
【注意】点阵屏旁边的跳线帽接三根排针中的右边两根
【操作】

	S1		S2		S3		S4
	S5		S6		S7		S8
	S9		S10		S11		S12
	S13		S14		S15		S16

S1~S9：数字1~9
S10：数字0
S11：清空/返回
S12：确认键

（1）输入错误可按S11（松手瞬间）清空后重新输入
（2）按S12（松手瞬间）表示确认完成输入
（3）猜对数字后按S11（松手瞬间）返回设置范围的界面
*/

#include <REGX52.H>	//51单片机头文件
#include "LCD1602.h"	//LCD1602液晶显示屏
#include "MatrixKeyScan.h"	//矩阵按键
#include "Timer0.h"	//定时器0
#include <STDLIB.H>	//随机函数

unsigned char KeyNum;	//存储获得的键码
unsigned char Mode;	//模式，0：显示游戏英文名，1：设置数字范围界面，2：猜数字过程，3：猜对后的屏幕显示
unsigned char OnceFlag = 1;	//某些前提下只执行一次的标志（各模式中用来判断是否要初始化），1：执行，0：不执行
unsigned char InputLength;	//输入位数，范围：1~4
unsigned char LastInputLength;	//上一次的输入位数，范围：1~4，用来判断是否有按下数字键0~9
bit ConfirmFlag;	//确认按键按下的标志，1：确认按键按下，0：确认按键未按下
unsigned char NowNumber;	//刚刚输入的数字按键对应的数字，范围：0~9
bit SetMinFlag;	//正在设置数字范围最小值的标志，1：正在设置，0：没有在设置
bit SetMaxFlag;	//正在设置数字范围最大值的标志，1：正在设置，0：没有在设置
unsigned int MinNumber;	//所设置的数字范围的最小值，范围：1~9997
unsigned int MaxNumber;	//所设置的数字范围的最大值，范围：3~9999
unsigned char MinLength;	//最小值的位数，范围：1~4
unsigned char MaxLength;	//最大值的位数，范围：1~4
bit CheckFlag;	//设置完范围后检查范围是否合理的标志，1：检查，0：不检查
bit ReenterFlag;	//重新输入的标志，1：重新输入，0：不重新输入
unsigned int PlayerNumber;	//玩家输入的数字，范围：2~9998
unsigned char PlayerLength;	//玩家输入数字的位数，范围：1~4
unsigned int RandomNumber;	//产生的随机数，范围：MinNumber<RandomNumber<MaxNumber
unsigned char RandomLength;	//随机数的位数，范围：1~4
unsigned int GuessTimes;	//玩家猜测的次数
unsigned char GuessLength;	//玩家猜测的次数的位数，范围：1~4

/**
  * 函    数：延时函数，延时约xms毫秒
  * 参    数：xms 延时的时间，范围：0~65535
  * 返 回 值：无
  */
void Delay(unsigned int xms)	//12T@11.0592MHz
{
	unsigned char i, j;
	while (xms--)
	{
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}

/**
  * 函    数：主函数（有且仅有一个）
  * 参    数：无
  * 返 回 值：无
  * 说    明：主函数是程序执行的起点，负责执行整个程序的主要逻辑‌
  */
void main()
{
	Timer0_Init();  //定时器0初始化
	LCD_Init();	//LCD1602初始化

	while (1)
	{
		KeyNum = MatrixKey();	//获取键码

		if (KeyNum)	//如果有按键按下
		{
			if (Mode == 0)	//如果是显示游戏名称的界面
			{
				if (KeyNum >= 33 && KeyNum <= 48)	//如果按下任意按键（松手瞬间）
				{
					Mode = 1;
					OnceFlag = 1;
				}
			}
			else if (Mode == 1)	//如果是设置数字范围的界面
			{
				if (KeyNum >= 33 && KeyNum <= 42)	//如果按下“0~9”（松手瞬间），即按下S1~S10，S10为0
				{
					if (InputLength < 4)	//限制输入的最大位数为4
					{
						if (InputLength != 0 || KeyNum != 42)	//第一个数字不能为0
						{
							NowNumber = (KeyNum - 32) % 10;
							InputLength++;
						}
					}
				}
				if (KeyNum == 27)	//如果按下S11（长按超1s）
				{
					OnceFlag = 1;	//重置
				}
				if (KeyNum == 43)	//如果按下S11（松手瞬间），则清空，重新输入
				{
					ReenterFlag = 1;
				}
				if (KeyNum == 44)	//如果按下S12（松手瞬间），表示确认
				{
					if (InputLength) { ConfirmFlag = 1; }	//按了数字键，才能确认
				}
			}
			else if (Mode == 2)	//如果是正在猜数字
			{
				if (KeyNum >= 33 && KeyNum <= 42)	//如果按下“0~9”（松手瞬间），即按下S1~S10，S10为0
				{
					if (InputLength < 4)	//限制输入的最大位数为4
					{
						if (InputLength != 0 || KeyNum != 42)	//第一个数字不能为0
						{
							NowNumber = (KeyNum - 32) % 10;
							InputLength++;
						}
					}
				}
				if (KeyNum == 27)	//如果按下S11（长按超1s）
				{
					Mode = 1;	//返回设置范围的界面
					OnceFlag = 1;
				}
				if (KeyNum == 43)	//如果按下S11（松手瞬间），则清空，重新输入
				{
					ReenterFlag = 1;
				}
				if (KeyNum == 44)	//如果按下S12（松手瞬间），表示确认
				{
					if (InputLength) { ConfirmFlag = 1; }	//按了数字键，才能确认
				}
			}
			else if (Mode == 3)	//如果是猜对之后的屏幕显示
			{
				if (KeyNum == 43)	//如果按下S11（松手瞬间）
				{
					Mode = 1;	//返回设置范围的界面
					OnceFlag = 1;
				}
			}

		}

		if (Mode == 0)	//显示游戏名称
		{
			if (OnceFlag)
			{
				OnceFlag = 0;	//标志置0

				/*初始化*/
				LCD_Clear();	//LCD1602清屏
				LCD_ShowString(1, 3, "Guess Number");	//显示游戏英文名
			}

		}

		else if (Mode == 1)	//设置要猜的数字的范围
		{
			if (OnceFlag)
			{
				OnceFlag = 0;

				//初始化
				LastInputLength = 0;	//上一次输入的位数清零
				InputLength = 0;	//输入的位数清零
				ConfirmFlag = 0;	//确认标志清零
				CheckFlag = 0;	//检查的标志置0
				ReenterFlag = 0;	//重新输入的标志置0
				SetMinFlag = 1;	//正在设置最小值的标志置1
				SetMaxFlag = 0;	//正在设置最大值的标志置0
				MinNumber = 0;	//最小值清零
				MaxNumber = 0;	//最大值清零
				MinLength = 0;	//最小值的位数清零
				MaxLength = 0;	//最大值的位数清零
				GuessTimes = 0;	//猜数字的次数清零
				LCD_Clear();	//清屏
				LCD_ShowString(1, 1, "Set Range");
				LCD_ShowString(2, 1, "Min:");
				LCD_ShowString(2, 9, "Max:");	//显示英文提示
				LCD_SetCursor(2, 5);	//设置光标在第2行第5列
				LCD_IsShowCursor(1);	//显示光标
			}
			if (LastInputLength != InputLength)	//如果按了S1~S10（0~9），S10为0
			{
				LastInputLength = InputLength;	//更新上一次的输入长度
				if (SetMaxFlag)	//如果正在设置最大值
				{
					LCD_ShowNum(2, 12 + InputLength, NowNumber, 1);	//将所按的数字显示在屏幕上
					MaxNumber *= 10; MaxNumber += NowNumber;	//将刚刚所按的数字键对应的数字保存到变量MaxNumber中
					MaxLength++;	//最大数字的位数增加一
				}
				if (SetMinFlag)	//如果正在设置最小值
				{
					LCD_ShowNum(2, 4 + InputLength, NowNumber, 1);	//将所按的数字显示在屏幕上
					MinNumber *= 10; MinNumber += NowNumber;
					MinLength++;
				}
			}
			if (ConfirmFlag || InputLength == 4)	//如果按了确认键，或者输入长度达到4
			{
				if (SetMaxFlag)	//如果是正在设置最大值
				{
					SetMaxFlag = 0;	//正在设置最大值的标志置0
					ConfirmFlag = 0;	//确认的标志置0
					LastInputLength = 0;
					InputLength = 0;

					CheckFlag = 1;	//检查范围是否合理的标志置1
				}
				if (SetMinFlag)	//如果是正在设置最小值
				{
					SetMinFlag = 0;	//正在设置最小值的标志置0
					ConfirmFlag = 0;
					LastInputLength = 0;
					InputLength = 0;

					LCD_SetCursor(2, 13);	//光标设置在第2行第13列
					SetMaxFlag = 1;	//正在设置最大值的标志置1
				}
			}
			if (CheckFlag)	//如果检查范围是否合理的标志为真
			{
				CheckFlag = 0;	//标志置0
				if (MinNumber + 1 < MaxNumber)	//如果最小值要比最大值小，且最小值和最大值要至少相差2
				{	//说明设置得合理
					Mode = 2;	//切换到玩家输入数字猜测的界面
					OnceFlag = 1;
				}
				else	//如果不合理
				{
					OnceFlag = 1;	//重置，即初始化
					LCD_ShowString(1, 14, "ERR");	//第一行后三个位置显示错误的英文的前三个字母
					Delay(1000);	//延时1s
				}
			}
			if (ReenterFlag)	//如果重新输入的标志为真
			{
				ReenterFlag = 0;	//标志置0
				if (SetMinFlag)	//如果是正在设置最小值
				{
					LastInputLength = 0;
					InputLength = 0;
					MinNumber = 0;
					MinLength = 0;
					LCD_ShowString(2, 5, "    ");	//清空显示
					LCD_SetCursor(2, 5);	//光标设置在第2行第5列
				}
				if (SetMaxFlag)	//如果是正在设置最大值
				{
					LastInputLength = 0;
					InputLength = 0;
					MaxNumber = 0;
					MaxLength = 0;
					LCD_ShowString(2, 13, "    ");	//清空显示
					LCD_SetCursor(2, 13);	//光标设置在第2行第13列
				}
			}
		}

		else if (Mode == 2)	//猜数字过程
		{
			if (OnceFlag)
			{
				OnceFlag = 0;

				//初始化
				LastInputLength = 0;
				InputLength = 0;
				ConfirmFlag = 0;
				srand(TL0);	//每次进入此if，以定时器低八位做随机数的种子
				//RandomNumber=(rand()%(MaxNumber-MinNumber-1)+MinNumber+1);	//这样也可以，但是发现产生的随机数很集中
				//按下面这样，利用定时器0的高低八位来使计算复杂一些，产生的随机数更加随机
				RandomNumber = ((rand() + TH0 * TL0 + TL0 / TH0) * (TH0 - TL0) % (MaxNumber - MinNumber - 1) + MinNumber + 1);//产生一个所设置范围内的随机数（不包含最小值和最大值）
				LCD_Clear();
				LCD_ShowString(1, 1, "Range:");
				LCD_ShowNum(1, 8, MinNumber, MinLength);
				LCD_ShowChar(1, 8 + MinLength, '~');	//显示一个右箭头→
				LCD_ShowNum(1, 9 + MinLength, MaxNumber, MaxLength);
				LCD_SetCursor(2, 1);	//设置光标在第2行第1列
			}
			if (LastInputLength != InputLength)
			{
				LastInputLength = InputLength;
				LCD_ShowNum(2, InputLength, NowNumber, 1);
				PlayerNumber *= 10; PlayerNumber += NowNumber;
				PlayerLength++;
			}
			if (ConfirmFlag || InputLength == 4)
			{
				ConfirmFlag = 0;
				LastInputLength = 0;
				InputLength = 0;
				GuessTimes++;	//每比较一次，猜的次数增加一

				if (PlayerNumber == RandomNumber)	//如果输入的数字跟随机数字相等
				{	//说明猜对了
					Mode = 3;	//切换到下一模式
					OnceFlag = 1;
				}
				else if (PlayerNumber<RandomNumber && PlayerNumber>MinNumber)	//如果输入数字小于随机数，且大于范围最小值
				{
					MinNumber = PlayerNumber;
					MinLength = PlayerLength;
				}
				else if (PlayerNumber > RandomNumber && PlayerNumber < MaxNumber)	//如果输入数字大于随机数，且小于范围最大值
				{
					MaxNumber = PlayerNumber;
					MaxLength = PlayerLength;
				}
				else	//如果不是以上情况，说明输入的数字不在范围内
				{
					GuessTimes--;	//输入错误不算次数
					LCD_ShowString(2, 14, "ERR");	//第2行最后三个位置显示错误的英文的前三个字母
					Delay(1000);	//延时1s
					LCD_ShowString(2, 14, "   ");	//清空三个英文字母的显示
				}
				PlayerNumber = 0;	//玩家输入的数字清0
				PlayerLength = 0;	//玩家输入数字的位数清零

				LCD_ShowString(1, 8, "         ");	//第1行右半屏清空显示
				LCD_ShowNum(1, 8, MinNumber, MinLength);
				LCD_ShowChar(1, 8 + MinLength, '~');
				LCD_ShowNum(1, 9 + MinLength, MaxNumber, MaxLength);	//根据玩家输入的数字显示缩小后的范围
				LCD_SetCursor(2, 1);

				LastInputLength = 0;
				InputLength = 0;
				LCD_ShowString(2, 1, "    ");	//清空玩家输入的数字
				LCD_SetCursor(2, 1);	//设置光标在第2行第1列
			}
			if (ReenterFlag)
			{
				ReenterFlag = 0;
				LastInputLength = 0;
				InputLength = 0;
				PlayerNumber = 0;	//玩家输入的数字清0
				PlayerLength = 0;	//玩家输入数字的位数清零
				LCD_ShowString(2, 1, "    ");
				LCD_SetCursor(2, 1);
			}

		}
		else if (Mode == 3)	//猜中之后的屏幕显示
		{
			if (OnceFlag)
			{
				OnceFlag = 0;

				LCD_Clear();

				LCD_ShowString(1, 1, "Yes!");
				LCD_ShowString(1, 6, "Number:");
				if (RandomNumber / 1000) { RandomLength = 4; }
				else if (RandomNumber / 100) { RandomLength = 3; }
				else if (RandomNumber / 10) { RandomLength = 2; }
				else { RandomLength = 1; }
				LCD_ShowNum(1, 13, RandomNumber, RandomLength);

				LCD_ShowString(2, 1, "Times:");
				if (GuessTimes / 1000) { GuessLength = 4; }
				else if (GuessTimes / 100) { GuessLength = 3; }
				else if (GuessTimes / 10) { GuessLength = 2; }
				else { GuessLength = 1; }
				LCD_ShowNum(2, 7, GuessTimes, GuessLength);

				LCD_IsShowCursor(0);
			}
		}


	}
}

/**
  * 函    数：定时器0中断函数
  * 参    数：无
  * 返 回 值：无
  */
void Timer0_Routine() interrupt 1
{
	static unsigned char T0Count1;	//定时器0计数变量
	TL0 = 0x00;	//设置定时初值，定时10ms，12T@11.0592MHz
	TH0 = 0xDC;	//设置定时初值，定时10ms，12T@11.0592MHz
	T0Count1++;
	if (T0Count1 >= 2)	//每隔20ms检测一次按键
	{
		T0Count1 = 0;
		MatrixKey_Tick();
	}
}
